package win.larryzeal.spring.jms.config;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.annotation.JmsListenerConfigurer;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerEndpointRegistrar;
import org.springframework.jms.config.SimpleJmsListenerEndpoint;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.jms.listener.MessageListenerContainer;
import org.springframework.jms.listener.adapter.MessageListenerAdapter;
import win.larryzeal.spring.jms.config.listener.MessageListenerOneImpl;

import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.TextMessage;

/**
 * Created by 张少昆 on 2017/8/4 0004.
 */
@PropertySource( "classpath:application.properties" )
@ComponentScan( basePackages = "win.larryzeal.spring" )
@Configuration
@EnableJms
public class JmsConfig implements JmsListenerConfigurer {

    @Value( "${activemq.url}" )
    private String amq_url;

    @Value( "${activemq.default.queue}" )
    private String defaultQueue;
    @Value( "${activemq.topic.test}" )
    private String topic;

    @Autowired
    private MessageListenerOneImpl messageListenerOneImpl;

    /**
     * 用来设置默认的destination，如果否则使用defaultDestinationName，则会同时创建Queue和Topic两种destination。
     */
    @Bean
    public Destination defaultDestination(){
        ActiveMQQueue activeMQQueue = new ActiveMQQueue(defaultQueue);
        return activeMQQueue;
    }

    @Bean( "topic-test" )
    public Destination topicTest(){
        ActiveMQTopic activeMQTopic = new ActiveMQTopic(topic);
        return activeMQTopic;
    }

    /**
     * JMS的ConnectionFactory实现，Spring提供了它的代理，见 @Bean( "connectionFactory" )
     *
     * @return
     */
    @Bean( "amqConnectionFactory" )
    public ConnectionFactory amqConnectionFactory(){
        return new ActiveMQConnectionFactory(amq_url);
    }

    /**
     * Spring提供的ConnectionFactory代理，可以缓存session等，并忽略close()调用。
     *
     * @return
     */
    @Bean( "connectionFactory" )
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
        cachingConnectionFactory.setTargetConnectionFactory(amqConnectionFactory());
        cachingConnectionFactory.setSessionCacheSize(100);//缓存多少个session
        return cachingConnectionFactory;
    }

    /**
     * 要么自己的监听器类继承MessageListenerAdapter，并注册成bean；要么在这里注册MessageListenerAdapter bean。<br />
     * 现在MessageListenerOneImpl 已经继承了MessageListenerAdapter，就不需要这个bean了
     *
     * @return
     */
    //@Bean
    public MessageListenerAdapter messageListener(){
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(messageListenerOneImpl);
        return messageListenerAdapter;
    }

    /**
     * 这个也不需要了，因为注解式监听器使用的是DefaultJmsListenerContainerFactory。
     *
     * @return
     */
    //@Bean
    public MessageListenerContainer messageListenerContainer(){
        DefaultMessageListenerContainer defaultMessageListenerContainer = new DefaultMessageListenerContainer();
        defaultMessageListenerContainer.setConnectionFactory(connectionFactory());
        defaultMessageListenerContainer.setDestinationName(defaultQueue);
        defaultMessageListenerContainer.setMessageListener(messageListener());
        // defaultMessageListenerContainer.afterPropertiesSet(); //auto invoke

        return defaultMessageListenerContainer;
    }

    @Bean
    public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(){
        DefaultJmsListenerContainerFactory factory =
                new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory());
        // factory.setDestinationResolver(destinationResolver()); //TODO
        factory.setConcurrency("5-10");//pool core size / pool max size

        return factory;
    }

    @Bean
    public JmsTemplate jmsTemplate(){
        JmsTemplate jmsTemplate = new JmsTemplate();
        jmsTemplate.setConnectionFactory(connectionFactory());
        jmsTemplate.setSessionAcknowledgeMode(Session.AUTO_ACKNOWLEDGE);
        jmsTemplate.setSessionTransacted(false);
        jmsTemplate.setMessageTimestampEnabled(true);
        //		jmsTemplate.setTimeToLive();
        //		jmsTemplate.setReceiveTimeout();
        //		jmsTemplate.setMessageIdEnabled();

        ActiveMQQueue activeMQQueue = new ActiveMQQueue(defaultQueue);
        jmsTemplate.setDefaultDestination(activeMQQueue); //

        return jmsTemplate;
    }

    @Bean
    public JmsMessagingTemplate jmsMessagingTemplate(){
        JmsMessagingTemplate jmsMessagingTemplate = new JmsMessagingTemplate();
        jmsMessagingTemplate.setConnectionFactory(connectionFactory());
        jmsMessagingTemplate.setJmsTemplate(jmsTemplate());
        //		jmsMessagingTemplate.setDefaultDestination();

        return jmsMessagingTemplate;
    }

    /**
     * 除了通过注解JmsListener配置之外，infrastructure 还允许你编码式配置端点。
     *
     * @param registrar
     */
    @Override
    public void configureJmsListeners(JmsListenerEndpointRegistrar registrar){
        SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();
        endpoint.setId("myJmsEndpoint");
        endpoint.setDestination(defaultQueue);
        endpoint.setMessageListener(message -> {
            try{
                System.out.println("编码式配置端点，收到消息：" + ((TextMessage) message).getText());
            } catch(JMSException e){
                e.printStackTrace();
            }
        });
        registrar.registerEndpoint(endpoint);
    }

}
